﻿@using BlazorWebassemblyMultiPagesTab.Client.Code
@using Microsoft.Extensions.Logging
@using System.Text
@inject ILoggerProvider LoggerProvider
@inject IJSRuntime JS

<!-- Display the tab headers -->

<ul class="nav-my-tab">
    <li class="leftbackward">
        <a href="#" onclick="@MoveLeft">
            <i class="bi bi-chevron-double-left"></i>
        </a>
    </li>
    <li class="rightforward">
        <a href="#" onclick="@CloseOther" title="关闭其他" style="border-right:1px #ddd solid">
            <i class="bi bi-x-circle"></i>
        </a>
        <a href="#" onclick="@MoveRight">
            <i class="bi bi-chevron-double-right"></i>
        </a>
    </li>
    <li class="middletab">
        <div class="middletab-tabs" style="left:@(0-OffsetLeft)px">
            <ul class="nav nav-tabs">
                @foreach (var item in Tabs)
                {
                    var tempItem = item;
                    <li @key="item" class="nav-item @(item.IsActive?"active":"")">
                        <a @onclick="@(async e =>await ActivateTab(tempItem))" class="nav-link" role="button">
                            @item.Title
                            <i class="bi bi-x" @onclick="@(async e =>await CloseTab(tempItem))"></i>
                        </a>
                    </li>
                }
            </ul>
        </div>
    </li>
</ul>


<div class="nav-tabs-body p-4" style="height: calc(100% - 100px);">
    @foreach (var item in Tabs)
    {
        <iframe @key="item" src="@item.Url" style="@item.Style"></iframe>
    }
</div>

@code {
    public List<Tab> Tabs { get; set; } = new List<Tab>();
    private static TabSet StaticTabSet { get; set; }
    private int OffsetLeft { get; set; }
    private void ClearActive()
    {
        foreach (var item in Tabs)
        {
            if (item.IsActive)
            {
                item.IsActive = false;
            }
        }
    }
    private async Task MoveLeft()
    {
        var tabsWidth = await JS.InvokeAsync<int>("GetWidth", ".middletab");
        MoveTo(OffsetLeft - tabsWidth);
    }
    private async Task MoveRight()
    {
        var tabsWidth = await JS.InvokeAsync<int>("GetWidth", ".middletab");

        var moveS = OffsetLeft + tabsWidth;
        var temp = 0;
        Tab soTab = null;
        foreach (var tab in Tabs)
        {
            temp += tab.TabWidth;
            if (temp > moveS)
            {
                soTab = tab;
                break;
            }
        }
        if (soTab == null)
        {
            soTab = Tabs.LastOrDefault();
        }
        if (soTab != null)
        {
            await ScrollToTab(soTab);
        }

    }
    private async Task CloseTab(Tab tab)
    {
        var index = Tabs.IndexOf(tab);
        Tabs.Remove(tab);
        LoggerProvider.CreateLogger("dd").LogWarning("CloseTab");

        if (tab.IsActive)
        {
            Tab activeTab = null;
            LoggerProvider.CreateLogger("dd").LogWarning("CloseTabIsActive" + index);
            if (index > 0)
            {
                activeTab = Tabs[index - 1];
            }
            else if (Tabs.Count > 0)
            {
                activeTab = Tabs[0];
            }
            if (activeTab != null)
            {
                await ActivateTab(activeTab);
            }
        }
    }
    private async Task CloseOther()
    {

        Tabs.RemoveAll(m => !m.IsActive);
        if (Tabs.Count > 0)
        {
            await ScrollToTab(Tabs.FirstOrDefault());
        }
    }
    private async Task ActivateTab(Tab tab)
    {
        LoggerProvider.CreateLogger("dd").LogWarning("ActivateTab" + tab.TabWidth);
        var tabsWidth = await JS.InvokeAsync<int>("GetWidth", ".middletab");
        var index = Tabs.IndexOf(tab);
        var sumWidth = Tabs.Take(index).Sum(m => m.TabWidth);
        var tabWidth = tab.TabWidth == 0 ? GetLength(tab.Title) * 8 + 20 : tab.TabWidth;
        if (sumWidth <= OffsetLeft || sumWidth + tabWidth >= OffsetLeft + tabsWidth)
        {
            var pre = index - 1;
            if (pre < 0)
            {
                pre = 0;
            }
            await ScrollToTab(Tabs[pre]);
        }
        ClearActive();
        tab.IsActive = true;

    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (Tabs == null)
        {
            return;
        }
        LoggerProvider.CreateLogger("dd").LogWarning("OnAfterRenderAsync");
        for (var i = 0; i < Tabs.Count; i++)
        {
            var item = Tabs[i];
            if (item.TabWidth <= 0)
            {
                item.TabWidth = await JS.InvokeAsync<int>("GetTabWidth", i);
                LoggerProvider.CreateLogger("dd").LogWarning("CloseTabIsActive" + i + "," + item.TabWidth);
            }
        }
        // TabsWidth = await JS.InvokeAsync<int>("GetWidth", ".middletab");
    }
    protected override async Task OnInitializedAsync()
    {
        LoggerProvider.CreateLogger("dd").LogWarning("OnInitializedAsync");
        StaticTabSet = this;
    }

    public async Task ScrollToTab(Tab tab)
    {
        var top = Tabs.IndexOf(tab);
        var offset = Tabs.Take(top).Sum(m => m.TabWidth);
        var other = Tabs.Skip(top).Sum(m => m.TabWidth == 0 ? GetLength(m.Title) * 8 + 20 : m.TabWidth);

        var tabsWidth = await JS.InvokeAsync<int>("GetWidth", ".middletab");
        if (offset + other < tabsWidth - 100)
        {
            OffsetLeft = 0;
            return;
        }
        if (other < tabsWidth - 100)
        {
            MoveTo(offset + other - tabsWidth + 100);
            LoggerProvider.CreateLogger("dd").LogWarning($"2OffsetLeft{OffsetLeft},{other},{offset},{tabsWidth}");
            return;
        }
        OffsetLeft = offset;
        LoggerProvider.CreateLogger("dd").LogWarning("3OffsetLeft" + OffsetLeft);

    }
    public static int GetLength(string str)
    {

        if (str.Length == 0) return 0;

        ASCIIEncoding ascii = new ASCIIEncoding();
        int tempLen = 0;
        byte[] s = ascii.GetBytes(str);
        for (int i = 0; i < s.Length; i++)
        {
            if ((int)s[i] == 63)
            {
                tempLen += 2;
            }
            else
            {
                tempLen += 1;
            }
        }

        return tempLen;
    }
    private void MoveTo(int x)
    {
        if (x <= 0)
        {
            OffsetLeft = 0;
            return;
        }
        var temp = 0;
        bool isSet = false;
        foreach (var item in Tabs)
        {
            if (temp + item.TabWidth > x)
            {
                isSet = true;
                temp += item.TabWidth;
                break;
            }
            temp += item.TabWidth;
        }
        if (isSet)
        {
            OffsetLeft = temp;
        }
        else
        {
            OffsetLeft = x;
        }
        LoggerProvider.CreateLogger("dd").LogWarning($"MoveTo{OffsetLeft},{x}");
    }
    public async Task RunAddTab(string title, string url)
    {
        bool has = false;
        Tab tab = null;
        foreach (var item in Tabs)
        {
            if (item.Title == title && item.Url == url)
            {
                tab = item;
            }
        }
        if (tab == null)
        {
            tab = new Tab { Title = title, Url = url, IsActive = true };
            Tabs.Add(tab);
        }
        await ActivateTab(tab);
        StateHasChanged();
    }
    public async Task RunGoTo(string title, string url)
    {
        var index = Tabs.FindIndex(m => m.IsActive);
        if (index < 0)
        {
            await RunAddTab(title, url);
            return;
        }
        Tabs[index] = new Tab { Title = title, Url = url, IsActive = true };
        StateHasChanged();

    }
    public async Task RunCloseTab()
    {
        var tab = Tabs.FirstOrDefault(m => m.IsActive);
        if (tab != null)
        {
            await CloseTab(tab);
        }
        StateHasChanged();
    }

    [JSInvokable]
    public static async void AddTab(string title, string url)
    {
        if (StaticTabSet != null)
        {
            await StaticTabSet.RunAddTab(title, url);
        }
    }

    [JSInvokable]
    public static async void GoTo(string title, string url)
    {
        if (StaticTabSet != null)
        {
            await StaticTabSet.RunGoTo(title, url);
        }
    }

    [JSInvokable]
    public async static void CloseTab()
    {

        if (StaticTabSet != null)
        {
            await StaticTabSet.RunCloseTab();
        }
    }
}